package monitoring.rawdata.analysis;

import static monitoring.utility.StaticFields.CONTENT_ELEM;
import static monitoring.utility.StaticFields.CONTENT_MIN_SIZE;
import static monitoring.utility.StaticFields.KEY_ELEM;
import static monitoring.utility.StaticFields.KEY_SIZE;
import static monitoring.utility.StaticFields.OUTB;

import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;


import store.hibernate.RawData;


public class DecomposingPacket {

	public DataObject parse(RawData rd){
		int minSize= KEY_SIZE + CONTENT_MIN_SIZE;
		byte[] key = rd.getIdKey();
		byte[] contentUDP = rd.getContent();

		if(KEY_ELEM[1]==4){
			int size=0;
			try{
				ByteBuffer bb = ByteBuffer.allocate(4);
				for(int i=KEY_ELEM[0];i<KEY_ELEM[0]+4;i++)
					bb.put(key[i]);
				bb.flip();
				size = bb.getInt();
			}catch(BufferUnderflowException e){
				return null;
			}
			

			if(size>0 && size>minSize){
				//System.out.println("dimensione pacchetto: "+size);
				int contentSize = size-KEY_SIZE;
				byte[] content = new byte[contentSize];
				for(int i=0;i<contentSize;i++)
					content[i]=contentUDP[i];

				DataObject dataO = new DataObject(key, content, size);
				if(keyParse(key, dataO) && contentParse(content, dataO)){
					return dataO;
				}
			}
		}

		return null;
	}
	
	private boolean keyParse(byte[] key, DataObject rdo) {
		int offset=0;
		for(int i=0;i<KEY_ELEM.length;i++){
			byte[] tmp=getFieldKey(key, offset, KEY_ELEM[i]);
			if(tmp!=null){
				switch(i){
				case 0: rdo.setDirection(tmp); break;
				case 1: break;
				case 2: rdo.setTimestamp(tmp); break;	
				case 3: rdo.setSession(tmp); break;
				}
				offset+=KEY_ELEM[i];
			}
			else
				return false;
		}
		return true;
	}
	
	

	private boolean contentParse(byte[] content, DataObject rdo) {
		ByteBuffer bb = ByteBuffer.allocate(4);
		int offset=0;
		/* se mi arriva un pacchetto OUTBOUND 
		 * recupero la KEY del pacchetto INBOUND */
		if(rdo.getDirection()[0]==OUTB){
			byte[] tmp=new byte[KEY_SIZE];
			for(int i=offset;i<KEY_SIZE+offset;i++)
				tmp[i-offset]=content[i];
			rdo.setKeyInbound(tmp);
			offset+=KEY_SIZE;
		}
		for(int i=0;i<CONTENT_ELEM.length;i++){
			byte[] tmp=getFieldContent(content, bb, offset, CONTENT_ELEM[i]);
			if(tmp!=null){
				switch(i){
				case 0: rdo.setSeqNumber(tmp); break;
				case 1: rdo.setUsername(tmp); break;
				case 2: rdo.setPassword(tmp); break;
				case 3: rdo.setApplURL(tmp); break;
				case 4: rdo.setWSNamespace(tmp); break;	
				case 5: rdo.setOperation(tmp); break;
				}
				offset+=CONTENT_ELEM[i]+tmp.length;
			}
			else
				return false;
		}
		int lenPar=content.length-offset;
		if(lenPar>0){	
			byte [] tmp=new byte[lenPar];
			for(int i=offset;i<lenPar+offset;i++)
				tmp[i-offset]=content[i];
			rdo.setParams(tmp);
		}
		return true;
	}

	
	private byte[] getFieldKey(byte[] b, int offset, int ByteDim) {
		byte[] b2= new byte[ByteDim];
		for(int i=offset;i<offset+ByteDim;i++){
			b2[i-offset]=b[i];
		}
		return b2;
	}
	
	private byte[] getFieldContent(byte[] b, ByteBuffer bb, int offset, int ByteDim){
		int len=0;
		if(ByteDim==4)
			len=integerControl(b, bb,offset);
		if(len>0){
			byte[] b2= new byte[len];
			offset+=ByteDim;
			for(int i=offset;i<len+offset;i++)
				b2[i-offset]=b[i];
			return b2;
		}
		return null;
	}
	
	private int integerControl(byte[] b, ByteBuffer bb, int offset){
		bb.clear();
		for(int i=offset;i<offset+4;i++)
			bb.put(b[i]);
		bb.flip();
		int length = bb.getInt();
		if(length>0)
			return length;
		return 0;
	}

}
